package com.free4inno.knowledgems.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.free4inno.knowledgems.dao.AttachmentDao;
import com.free4inno.knowledgems.dao.ResourceDao;
import com.free4inno.knowledgems.dao.SystemManageDao;
import com.free4inno.knowledgems.dao.TemplateDao;
import com.free4inno.knowledgems.domain.Attachment;
import com.free4inno.knowledgems.domain.GroupInfo;
import com.free4inno.knowledgems.domain.Resource;
import com.free4inno.knowledgems.domain.Template;
import com.free4inno.knowledgems.service.LabelService;
import com.free4inno.knowledgems.service.ResourceEsService;
import com.free4inno.knowledgems.service.ResourceService;
import com.free4inno.knowledgems.service.UserService;
import com.free4inno.knowledgems.utils.Constants;
import com.free4inno.knowledgems.utils.ImageUtils;
import com.free4inno.knowledgems.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import java.sql.Timestamp;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * Author HaoYi.
 * Date 2020/9/16.
 */

@Slf4j
@Controller
@RequestMapping("crudres")
public class CrudResController {

    @Autowired
    private ResourceDao resourceDao;

    @Autowired
    private AttachmentDao attachmentDao;

    @Autowired
    private TemplateDao templateDao;

    @Autowired
    private LabelService labelService;

    @Autowired
    private UserService userService;

    @Autowired
    private ResourceEsService esService;

    @Autowired
    private ResourceService resourceService;

    @Autowired
    private SystemManageDao systemManageDao;

    @Autowired
    private ImageUtils imageUtils;

    @RequestMapping("new")
    public String newApp(HttpSession session, Map param) {
        log.info(this.getClass().getName() + "----in----" + "新建(new)" + "----" + session.getAttribute(Constants.USER_ID));
        // get groupList
        Integer userId = Integer.parseInt(session.getAttribute(Constants.USER_ID).toString());
        List<GroupInfo> groupInfoList = userService.userGroupInfosAll(userId);
        param.put("groupInfoList", groupInfoList);
        // get templateList
        List<Template> templateInfoList = templateDao.findAll();
        param.put("templateInfoList", templateInfoList);
        // get book label id
        String bookLabelId = systemManageDao.findAllByVariable("book_label").get().getValue();
        param.put("bookLabelId", bookLabelId);
        log.info(this.getClass().getName() + "----out----" + "跳转到新建页面" + "----" + session.getAttribute(Constants.USER_ID));
        return "crud/newres";
    }

    @ResponseBody
    @GetMapping("getTemplateCode")
    public Map<String, Object> getTemplateCode(@RequestParam("id") Integer id, HttpSession session) {
        log.info(this.getClass().getName() + "----in----" + "获取模板编码(getTemplateCode)" + "----" + session.getAttribute(Constants.USER_ID));
        Map<String, Object> jsonObject = new HashMap<>();
        String templateCode = templateDao.findById(id).get().getTemplateCode();
        jsonObject.put("templateCode", templateCode);
        jsonObject.put("code", 200);
        jsonObject.put("msg", "OK");
        log.info(this.getClass().getName() + "----out----" + "返回获取到的模板编码" + "----" + session.getAttribute(Constants.USER_ID));
        return jsonObject;
    }

    @ResponseBody
    @GetMapping("getLabel")
    public Map<String, Object> getLabels(HttpSession session) {
        log.info(this.getClass().getName() + "----in----" + "获取标签(getLabel)" + "----" + session.getAttribute(Constants.USER_ID));
        Map<String, Object> jsonObject = new HashMap<>();
        List<List<Map<String, String>>> tagList = labelService.getLabels();
        jsonObject.put("code", 200);
        jsonObject.put("msg", "OK");
        jsonObject.put("result", tagList);
        log.info(this.getClass().getName() + "----out----" + "返回获取到的标签列表" + "----" + session.getAttribute(Constants.USER_ID));
        return jsonObject;
    }

    @RequestMapping("newdata")
    @ResponseBody
    public Map<String, Object> newResource(@RequestParam("title") String title,
                                           @RequestParam("group") String group,
                                           @RequestParam("label") String label,
                                           @RequestParam("text") String text,
                                           @RequestParam("attachment") String attachmentJson,
                                           @RequestParam("superior") Integer superior,
                                           @RequestParam("contents") String contents,
                                           HttpSession session,
                                           HttpServletRequest request) throws Exception {
        log.info(this.getClass().getName() + "----in----" + "保存新建资源(newdata)" + "----" + session.getAttribute(Constants.USER_ID));
        Map<String, Object> jsonObject = new HashMap<>();
        if (title.equals("") || text.equals("")) {
            jsonObject.put("msg", "必填项未填写完整");
            log.info(this.getClass().getName() + "----out----" + "保存新建资源失败(必填项未填写完整)" + "----" + session.getAttribute(Constants.USER_ID));
            return jsonObject;
        }
        List<String> imageSrc = imageUtils.getImgSrc(text);
        //获得真实路径
        String realPath = request.getSession().getServletContext().getResource("/").getPath();
        int index = realPath.indexOf("/");
        realPath = realPath.substring(index);
        int index2 = realPath.lastIndexOf("/knowledgems-1.0-SNAPSHOT");
        if (index2 != -1) {
            realPath = realPath.substring(0, index2);
        }
        //计算程序运行时长的线程池
        final ExecutorService exec = Executors.newFixedThreadPool(1);
        //下载图片，并把img src替换为本地路径
        log.info(this.getClass().getName() + "----" + "下载图片，并把img src替换为本地路径" + "----" + session.getAttribute(Constants.USER_ID));
        for (String src : imageSrc) {
            String finalRealPath = realPath;
            Callable<String[]> call = new Callable<String[]>() {
                public String[] call() throws Exception {
                    //开始执行下载图片操作
                    //**********重要！！download函数内部下载时有一个5s下载时长限制，如若调整下载等待时间，一定要调函数内部**********
                    String[] resultArray = imageUtils.download(src, finalRealPath);
                    //**********重要！！download函数内部下载时有一个5s下载时长限制，如若调整下载等待时间，一定要调函数内部**********
                    return resultArray;
                }
            };
            try {
                //控制程序运行时间
                Future<String[]> future = exec.submit(call);
                //**********重要！！下载图片函数超时时间设为 6 秒，超时则报异常**********
                String[] resultArray = future.get(1000 * 6, TimeUnit.MILLISECONDS);
                if (resultArray[0].substring(0, 1).equals("2")) {
                    String newsrc = resultArray[1];
                    log.debug(this.getClass().getName() + "----" + "newdata()" + "----success----" + "图片链接：" + newsrc + "----" + session.getAttribute(Constants.USER_ID));
                    text = text.replace(src, newsrc);
                } else if (resultArray[0].substring(0, 1).equals("l")) {
                    log.debug(this.getClass().getName() + "----" + "newdata()" + "----success----" + "图片下载结果：" + resultArray[1] + "----" + session.getAttribute(Constants.USER_ID));
                } else {
                    log.error(this.getClass().getName() + "----" + "newdata()" + "----failure----" + "图片下载出现问题，提示：" + resultArray[0]
                            + "。下载链接为：" + resultArray[1] + "----" + session.getAttribute(Constants.USER_ID));
                    break;
                }
            } catch (TimeoutException e) {
                e.printStackTrace();
                log.error(this.getClass().getName() + "----" + "newdata()" + "----failure----" + "下载外链图片超时" + "----" + session.getAttribute(Constants.USER_ID));
                break; //下载出问题则不再下载图片，直接返回
            } catch (Exception e) {
                e.printStackTrace();
                log.error(this.getClass().getName() + "----" + "newdata()" + "----failure----" + "下载外链图片时出现未知问题" + "----" + session.getAttribute(Constants.USER_ID));
                break; //下载出问题则不再下载图片，直接返回
            }
        }
        // 关闭线程池
        exec.shutdown();
        Integer userId = (Integer) session.getAttribute(Constants.USER_ID);
        Resource resource = new Resource();
        resource.setUserId(userId);
        resource.setCreateTime(new Timestamp(new Date().getTime()));
        resource.setEditTime(new Timestamp(new Date().getTime()));
        resource.setTitle(title);
        resource.setText(text);
        resource.setPermissionId(0); //默认为不公开资源
        resource.setSuperior(superior);
        resource.setGroupId(group);
        resource.setLabelId(label);
        resource.setContents(contents);
        resourceDao.saveAndFlush(resource);
        esService.addResourceES(resource.getId());

        //保存附件信息
        log.info(this.getClass().getName() + "----" + "保存附件信息" + "----" + session.getAttribute(Constants.USER_ID));
        JSONArray attachmentJsonArray = JSON.parseArray(attachmentJson);
        for (int i = 0; i < attachmentJsonArray.size(); i++) {
            JSONObject attachmentJsonObject = attachmentJsonArray.getJSONObject(i);
            Attachment attachment = new Attachment();
            attachment.setResourceId(resource.getId());
            attachment.setCreateTime(new Timestamp(new Date().getTime()));
            attachment.setName(attachmentJsonObject.getString("name"));
            attachment.setUrl(attachmentJsonObject.getString("url"));
            attachment.setStatus(Attachment.AttachmentEnum.READY);
            attachmentDao.saveAndFlush(attachment);
        }
        jsonObject.put("msg", "SUCCESS");
        jsonObject.put("resourceId", resource.getId());
        log.info(this.getClass().getName() + "----out----" + "保存新建资源成功，返回资源id" + "----" + session.getAttribute(Constants.USER_ID));
        return jsonObject;
    }

    @RequestMapping("edit")
    public String editResource(@RequestParam("id") Integer id, HttpSession session, Map param) {
        log.info(this.getClass().getName() + "----in----" + "编辑(edit)" + "----" + session.getAttribute(Constants.USER_ID));

        Resource resource = resourceDao.findById(id).get();
//        System.out.print("初始数据："+resource.getText());
        resource.setTitle(StringUtils.inputStringFormat(resource.getTitle()));
        resource.setText(StringUtils.inputStringFormat(resource.getText()));
//        System.out.print("处理后数据："+resource.getText());

        Integer userId = Integer.parseInt(session.getAttribute(Constants.USER_ID).toString());
        List<GroupInfo> groupInfoList = userService.userGroupInfosAll(userId);
        param.put("groupInfoList", groupInfoList);
        param.put("resource", resource);
        //取资源的附件
        String attachment = resourceService.getAttachmentJson(id);
        param.put("attachment", attachment);
        // get templateList
        List<Template> templateInfoList = templateDao.findAll();
        param.put("templateInfoList", templateInfoList);
        // get book label id
        String bookLabelId = systemManageDao.findAllByVariable("book_label").get().getValue();
        param.put("bookLabelId", bookLabelId);
        log.info(this.getClass().getName() + "----out----" + "跳转到编辑资源页面" + "----" + session.getAttribute(Constants.USER_ID));
        return "crud/editres";
    }

    @RequestMapping("editdata")
    @ResponseBody
    public Map<String, Object> editdata(@RequestParam("id") Integer id,
                                        @RequestParam("title") String title,
                                        @RequestParam("group") String group,
                                        @RequestParam("label") String label,
                                        @RequestParam("text") String text,
                                        @RequestParam("attachment") String attachmentJson,
                                        @RequestParam("superior") Integer superior,
                                        @RequestParam("contents") String contents,
                                        HttpSession session,
                                        HttpServletRequest request) throws Exception {
        log.info(this.getClass().getName() + "----in----" + "保存编辑资源(editdata)" + "----" + session.getAttribute(Constants.USER_ID));
        Map<String, Object> jsonObject = new HashMap<>();
        Resource resource = resourceDao.findById(id).get();
        if (title.equals("") || text.equals("")) {
            jsonObject.put("msg", "必填项未填写完整");
            log.info(this.getClass().getName() + "----out----" + "保存编辑资源失败(必填项未填写完整)" + "----" + session.getAttribute(Constants.USER_ID));
            return jsonObject;
        }
//        System.out.print("保存初始数据："+text);
        List<String> imageSrc = imageUtils.getImgSrc(text);
        //获得真实路径
        String realPath = request.getSession().getServletContext().getResource("/").getPath();
        int index = realPath.indexOf("/");
        realPath = realPath.substring(index);
        int index2 = realPath.lastIndexOf("/knowledgems-1.0-SNAPSHOT");
        if (index2 != -1) {
            realPath = realPath.substring(0, index2);
        }
        //计算程序运行时长的线程池
        final ExecutorService exec = Executors.newFixedThreadPool(1);
        //下载图片，并把img src替换为本地路径
        log.info(this.getClass().getName() + "----" + "下载图片，并把img src替换为本地路径" + "----" + session.getAttribute(Constants.USER_ID));
        for (String src : imageSrc) {
            String finalRealPath = realPath;
            Callable<String[]> call = new Callable<String[]>() {
                public String[] call() throws Exception {
                    //开始执行下载图片操作
                    //**********重要！！download函数内部下载时有一个5s下载时长限制，如若调整下载等待时间，一定要调函数内部**********
                    String[] resultArray = imageUtils.download(src, finalRealPath);
                    //**********重要！！download函数内部下载时有一个5s下载时长限制，如若调整下载等待时间，一定要调函数内部**********
                    return resultArray;
                }
            };
            try {
                //控制程序运行时间
                Future<String[]> future = exec.submit(call);
                //**********重要！！下载图片函数超时时间设为 6 秒，超时则报异常**********
                String[] resultArray = future.get(1000 * 6, TimeUnit.MILLISECONDS);
                if (resultArray[0].substring(0, 1).equals("2")) {
                    String newsrc = resultArray[1];
                    log.debug(this.getClass().getName() + "----" + "newdata()" + "----success----" + "图片链接：" + newsrc + "----" + session.getAttribute(Constants.USER_ID));
                    text = text.replace(src, newsrc);
                } else if (resultArray[0].substring(0, 1).equals("l")) {
                    log.debug(this.getClass().getName() + "----" + "newdata()" + "----success----" + "图片下载结果：" + resultArray[1] + "----" + session.getAttribute(Constants.USER_ID));
                } else {
                    log.error(this.getClass().getName() + "----" + "newdata()" + "----failure----" + "图片下载出现问题，提示：" + resultArray[0]
                            + "。下载链接为：" + resultArray[1] + "----" + session.getAttribute(Constants.USER_ID));
                    break;
                }
            } catch (TimeoutException e) {
                e.printStackTrace();
                log.error(this.getClass().getName() + "----" + "newdata()" + "----failure----" + "下载外链图片超时" + "----" + session.getAttribute(Constants.USER_ID));
                break; //下载出问题则不再下载图片，直接返回
            } catch (Exception e) {
                e.printStackTrace();
                log.error(this.getClass().getName() + "----" + "newdata()" + "----failure----" + "下载外链图片时出现未知问题" + "----" + session.getAttribute(Constants.USER_ID));
                break; //下载出问题则不再下载图片，直接返回
            }
        }
        // 关闭线程池
        exec.shutdown();
//        System.out.print(imageSrc);
        resource.setTitle(title);
        resource.setText(text);
        resource.setGroupId(group);
        resource.setEditTime(new Timestamp(new Date().getTime()));
        resource.setLabelId(label);
        resource.setSuperior(superior);
        resource.setContents(contents);
        resourceDao.saveAndFlush(resource);
        esService.updateResourceES(resource.getId());
        //保存附件信息
        log.info(this.getClass().getName() + "----" + "保存附件信息" + "----" + session.getAttribute(Constants.USER_ID));
        JSONArray attachmentJsonArray = JSON.parseArray(attachmentJson);
        for (int i = 0; i < attachmentJsonArray.size(); i++) {
            JSONObject attachmentJsonObject = attachmentJsonArray.getJSONObject(i);
            Attachment attachment = new Attachment();
            attachment.setResourceId(id);
            attachment.setCreateTime(new Timestamp(new Date().getTime()));
            attachment.setName(attachmentJsonObject.getString("name"));
            attachment.setUrl(attachmentJsonObject.getString("url"));
            attachment.setStatus(Attachment.AttachmentEnum.READY);
            attachmentDao.saveAndFlush(attachment);
        }
        jsonObject.put("msg", "SUCCESS");
        log.info(this.getClass().getName() + "----out----" + "保存编辑资源成功，返回成功json" + "----" + session.getAttribute(Constants.USER_ID));
        return jsonObject;
    }
}
